/*
 * MetaballGroup.h
 *
 *  Created on: 2010-09-22
 *      Author: michal
 */

#ifndef METABALLGROUP_H_
#define METABALLGROUP_H_

#include <limits>
#include <vector>
#include "Object.h"

using namespace std;

#define SMALL_RAY_STEP  0.03f
#define BIG_RAY_STEP    0.5f
#define MAX_RAY_LENGTH  50.0f

struct Vert : public std::vector<float>
 {};

class Graph
{
      // ...
      typedef std::vector<Vert>::iterator vIt;
};

struct Metaball
{
	Metaball(Vec3 center, float radius = 1.0f, Material material = Material()) :
		_center(center), _radius(radius), _material(material)
	{
	}
	Vec3 _center;
	float _radius;
	Material _material;
};

class MetaballGroup : public Object
{
public:
	MetaballGroup();
	virtual ~MetaballGroup();

	Metaball * CreateMetaball();

	typedef vector<Metaball>::iterator BallIter;
	vector<Metaball> _balls;

	inline bool isInsideMetaball(const Vec3 & point)
	{
		float fieldStrength = 0.0f;

		for (BallIter it = _balls.begin(); it != _balls.end(); it++)
		{
			Vec3 dist = it->_center - point;

			fieldStrength += it->_radius / (dist.x * dist.x + dist.y * dist.y
							+ dist.z * dist.z);

			if (fieldStrength > 1.0f)
				return true;
		}

		return false;
	}

	float Intersect(const Ray & ray)
	{
		Vec3 rayCurPos = ray._origin;
		Vec3 bigRayStep = ray._direction * BIG_RAY_STEP;
		Vec3 smallRayStep = ray._direction * SMALL_RAY_STEP;
		for (float t = 0.0f; t < MAX_RAY_LENGTH; t += BIG_RAY_STEP) // Check ray taking big steps.
		{
			rayCurPos += bigRayStep;

			if(isInsideMetaball(rayCurPos)) // If jumped into field...
			{
				for(float t2 = t ; t2 > t-BIG_RAY_STEP ; t2 -= SMALL_RAY_STEP) // ...start from here and take small steps back...
				{
					rayCurPos -= smallRayStep;
					if(!isInsideMetaball(rayCurPos)) // ...until again outside the field.
						return t2 + SMALL_RAY_STEP; // Then take one step forward (again into field) and return it.
				}
			}
		}

		return numeric_limits<float>::infinity();
	}

	virtual IntersectionInfo GetIntersectionInfo(const Vec3 & point);
};

#endif /* METABALLGROUP_H_ */
